import axios from 'axios'
import { Loading } from 'element-ui'
import router from '@/router'

// ajax统一配置
const instance = axios.create({
  method: 'get',
  baseURL: '',
  timeout: 1000 * 300,
  responseType: 'json'
})

const handleWithParameter = function (
  url,
  {
    method = 'GET',
    contentType = 'application/json; charset=UTF-8',
    params = {},
    data = {},
    responseType = 'json',
    config = {}
  }
) {
  const { headers } = instance.defaults
  const parameters = {
    'Content-Type': contentType
  }
  const authToken = sessionStorage.getItem('GdToken') || ''
  if (authToken) {
    parameters.Authorization = 'Bearer ' + authToken
  }
  parameters.responseType = responseType

  instance.defaults.headers = { ...headers, ...parameters }

  // url替换参数
  let urlNew = url
  const paramsNew = { ...params }
  /*eslint-disable*/
  for (const key in params) {
    const reg = new RegExp(`:${key}`, 'g')
    if ({}.hasOwnProperty.call(params, key) && reg.test(urlNew)) {
      urlNew = urlNew.replace(reg, params[key])
      delete paramsNew[key]
    }
  }
  switch (method.toLowerCase()) {
    case 'get':
      return instance.get(
        urlNew,
        { params: paramsNew, ...config },
        {
          responseType
        }
      )
    case 'delete':
      return instance.delete(urlNew, { params: paramsNew })
    case 'post':
      return instance.post(urlNew, data, config)
    case 'put':
      return instance.put(urlNew, data, config)
    default: {
      const res = {
        then: resolve =>
          resolve({
            statusCode: 300,
            msg: 'method方式错误'
          })
      }
      return Promise.resolve(res)
    }
  }
}

/*
 * pre: ajax提交前
 * success: ajax连接成功返回正确结果后
 * error: ajax连接成功返回错误结果后
 * fail: ajax连接失败（网络错误）
 * always: ajax无论成功与失败都要执行
 */
const suffix = ['pre', 'success', 'error', 'fail', 'always']

let loadingCnt = 0
let noLoading = true
let loadingInstance = null

const createActions = function (actionMap) {
  const eventNames = Object.keys(actionMap)
  const fnsMap = {}
  eventNames.forEach(eventName => {
    const configOrFn = actionMap[eventName]
    if (typeof configOrFn !== 'function') {
      const config = { hasLoading: true, ...configOrFn }
      fnsMap[eventName] = ({ commit }, payload = {}) => {
        const handleRoot = { root: false }
        const showLoading = config.hasLoading || config.hasLoading === undefined
        const { conf, ...payloadOther } = payload

        if (showLoading) {
          loadingCnt++
          if (noLoading) {
            noLoading = false
            loadingInstance = Loading.service({
              lock: true,
              // text: '加载中…',
              background: 'rgba(255, 255, 255, 1)',
              customClass: 'loading-text'
            })
          }
        }
        if (config.actionType) {
          commit(`${config.actionType}_PRE`, payloadOther, handleRoot)
        }
        return handleWithParameter(config.url, {
          ...payloadOther,
          ...config
        })
          .then(res => {
            loadingInstance?.close()

            const { statusCode, message } = res.data
            const params =
              res.config.params === undefined
                ? res.config.data
                : res.config.params

            let dataRes
            // 是否需要接口传递的参数
            if (config.needFormData) {
              dataRes = { data: res }
            } else {
              dataRes =
                res.data.data === undefined
                  ? {
                      ...res.data,
                      data:
                        typeof params === 'string' ? JSON.parse(params) : params
                    }
                  : res.data
            }

            if (res.headers['content-disposition']) {
              return {
                data: res.data,
                contentDisposition: res.headers['content-disposition']
              }
            }

          // always只有在成功时才返回数据，非200或异常都不返回数据
          if (statusCode === 200) {
            if (config.actionType) {
              commit(`${config.actionType}_SUCCESS`, dataRes.data, handleRoot)
              commit(`${config.actionType}_ALWAYS`, dataRes.data, handleRoot)
            }
            return res.data
          } else {
            if (config.handleError || config.handleError === undefined) {
              if (statusCode === 401) {
                location.replace(location.origin)
              } else if(statusCode === 602) {
                // 用户冻结或者没有默认权限，返回602
                // TODO 待测试
                router.push({
                  name: 'error-page',
                  query: {
                    tip: message
                  }
                })
              } else {
                if (statusCode === 330) {
                  console.log(`${config.url}接口出错，请稍后重试!`)
                }
              }
            }

            if (config.actionType) {
              commit(`${config.actionType}_ERROR`, 'message', handleRoot)
              commit(`${config.actionType}_ALWAYS`, null, handleRoot)
            }
            return res.data
          }
        }).catch(error => {
          loadingInstance?.close()
          if (error.response) {
            let message = ''
            switch (error.response.status) {
              case 400:
                message = '请求错误'
                break
              case 401:
                message = '登录失效'
                window.projectApp.$toast({
                  message: '登录信息过期，自动刷新后重新登录',
                  type: 'fail',
                  duration: 6 * 1000,
                  onClose: function () {
                    location.reload()
                  }
                })
                break
              case 403:
                message = '拒绝访问'
                break
              case 404:
                message = `请求地址出错: ${error.response.config.url}`
                break
              case 408:
                message = '请求超时'
                break
              case 500:
                message = '服务器内部错误'
                break
              case 501:
                message = '服务未实现'
                break
              case 502:
                message = '网关错误'
                break
              case 503:
                message = '服务不可用'
                break
              case 504:
                message = '网关超时'
                break
              case 505:
                message = 'HTTP版本不受支持'
                break
              default:
                break
            }
            if (config.actionType) {
              commit(`${config.actionType}_FAIL`, null, handleRoot)
              commit(`${config.actionType}_ALWAYS`, null, handleRoot)
            }
            if (error.response.status === 500 && (config.url.endsWith('manage/authorize'))) {
              console.log(`${config.url}接口出错，请稍后重试! ${error.response.status}`)
            } else {
              window.projectApp.$toast({
                message: `${config.url}接口出错，请稍后重试! ${error.response.status}`,
                type: 'fail'
              })
            }
          } else {
            if (config.showErrorStack) {
              window.projectApp.$toast({
                message: `${error.message}！${error.stack}!`,
                // message: '数据量过大，30秒内未返回数据!',
                type: 'fail'
              })
            }
          }
        }).finally(() => {
          if (showLoading) {
            loadingCnt--
          }
          // console.log(loadingCnt, 'loadingCnt');
          if (loadingCnt <= 0) {
            loadingInstance?.close()
            noLoading = true
          }
        })
      }
    } else {
      fnsMap[eventName] = configOrFn
    }
  })
  return fnsMap
}

const handleMutations = function (mutationsMap) {
  const result = { ...mutationsMap }
  Object.keys(result).forEach(actionType => {
    const fnOrObject = result[actionType]
    if (fnOrObject && typeof fnOrObject !== 'function') {
      delete result[actionType]
      const keys = Object.keys(fnOrObject)
      // 补充没有的默认配置
      suffix.forEach(str => {
        if (!keys.includes(str)) {
          keys.push(str)
          fnOrObject[str] = () => {}
        }
      })

      keys.forEach(suffixAction => {
        result[`${actionType}_${suffixAction.toUpperCase()}`] =
          fnOrObject[suffixAction]
      })
    }
  })

  return result
}

export { createActions, handleMutations }
export default handleWithParameter
